package cn.jstars.datatocloud.modules.monitor.task;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.nutz.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;

import cn.jstars.datatocloud.common.cache.Cache;
import cn.jstars.datatocloud.common.consts.Consts.DBConst;
import cn.jstars.datatocloud.common.consts.Consts.DataType;
import cn.jstars.datatocloud.common.utils.DataUtil;
import cn.jstars.datatocloud.common.utils.DateUtil;
import cn.jstars.datatocloud.common.utils.PageUtil;
import cn.jstars.datatocloud.modules.base.MqService;
import cn.jstars.datatocloud.modules.monitor.entity.Toimachinestatus;
import cn.jstars.datatocloud.modules.monitor.service.MonitorService;

/**
 * 实时监控数据级联任务类
 * 
 * @author Elvish
 *
 */
public class MonitorTask implements Runnable {

	private static final Logger LOGGER = LoggerFactory.getLogger(MonitorTask.class);

	private MqService mqService;
	private MonitorService monitorService;
	private String year;
	private long historyTaskDayIntervalTime;

	public MonitorTask(MqService mqService, MonitorService monitorService, int year, long historyTaskDayIntervalTime) {
		this.mqService = mqService;
		this.monitorService = monitorService;
		this.year = year + "";
		this.setHistoryTaskDayIntervalTime(historyTaskDayIntervalTime);
	}

	@Override
	public void run() {

		// 获取今天，昨天，前天日期
		List<String> allDays = DateUtil.getNearlyDays(2);

		for (String day : allDays) {

			try {
				// 为了防止内存溢出，每次查询1W条
				List<Toimachinestatus> dataList = monitorService.findAllWithoutUpload(year, day);

				// 当天没有数据就级联下一天
				if (Lang.isEmpty(dataList)) {
					continue;
				}

				// 根据machineNo分组
				Map<String, List<Toimachinestatus>> groupMap = dataList.stream()
						.collect(Collectors.groupingBy(Toimachinestatus::getMachineno));

				// 替换机台编码前缀
				replaceMachinePrefix(groupMap);

				// 根据分组循环切分集合大小并发送且更新数据库状态
				for (Entry<String, List<Toimachinestatus>> entry : groupMap.entrySet()) {

					List<Toimachinestatus> list = entry.getValue();

					// 切分集合大小，500
					List<List<Toimachinestatus>> pageList = PageUtil.paging(list, 500);

					for (List<Toimachinestatus> tmsList : pageList) {

						try {
							sendMessage(tmsList, entry.getKey(), day);
						} catch (Exception e) {
							break;
						}

						monitorService.updateUploadStatus(tmsList, year, day);

						// 为了适应硬件差，缓慢执行
						Thread.sleep(1000);

					}

				}
			} catch (Exception e) {
				LOGGER.error("实时数据级联错误", e);
			}
			// 设置间隔时间，防止数据库崩溃,默认1分钟
			// Thread.sleep(historyTaskDayIntervalTime);
		}

	}

	/**
	 * 替换机台编码前缀
	 * 
	 * @param groupMap
	 */
	private void replaceMachinePrefix(Map<String, List<Toimachinestatus>> groupMap) {

		for (Entry<String, List<Toimachinestatus>> entry : groupMap.entrySet()) {
			// 获取机台编码
			String machineNo = entry.getKey();

			for (Toimachinestatus toimachinestatus : entry.getValue()) {
				// 机器编码需要替换
				toimachinestatus.setMachineno(Cache.factoryName + "-" + machineNo);
			}
		}

	}

	/**
	 * 发送消息
	 * 
	 * @param dataList
	 *            数据集合
	 * @param machineNo
	 *            原工厂机台编码
	 * @param day
	 *            具体日期
	 * @throws Exception
	 */
	private void sendMessage(List<Toimachinestatus> dataList, String machineNo, String day) throws Exception {
		String toiMachineStatusModelGroups = JSONObject.toJSONString(dataList);

		Map<String, String> toiMachineStatusMap = Maps.newHashMap();
		toiMachineStatusMap.put("ToiMachineStatus", toiMachineStatusModelGroups);

		Map<String, Object> dataMap = Maps.newHashMap();
		dataMap.put("MachineNo", machineNo);
		dataMap.put("ToiMachineStatusModelGroups", toiMachineStatusMap);

		// 封装数据
		String sendMsg = DataUtil.getMessage(DataType.MONITOR_DATA, DBConst.COUNTON_PREFIX + year,
				"toimachinestatus_" + day, Cache.factoryId, dataMap);

		// 发送数据至云端
		mqService.convertAndSend(Cache.cloudMQQueueName, sendMsg);
	}

	public long getHistoryTaskDayIntervalTime() {
		return historyTaskDayIntervalTime;
	}

	public void setHistoryTaskDayIntervalTime(long historyTaskDayIntervalTime) {
		this.historyTaskDayIntervalTime = historyTaskDayIntervalTime;
	}

}
